package com.stylefeng.guns.rest.domain;

import com.alibaba.fastjson.JSON;
import com.stylefeng.guns.core.util.Convert;
import com.stylefeng.guns.rest.common.exception.BizExceptionEnum;
import com.stylefeng.guns.rest.common.exception.ParamException;
import com.stylefeng.guns.rest.common.util.BeanUtils;
import com.stylefeng.guns.rest.common.util.StringUtils;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;


/**
 * @description: 封装请求参数
 * @date: 2017年8月10日 下午9:19:19
 * @version: V1.0
 */
@SuppressWarnings("serial")
public class ParamMap extends HashMap<String, Object> {

	public ParamMap(){
	}
	public ParamMap(Map<String, Object> map){
		this.putAll(map);
	}
	public static ParamMap init() {
		return new ParamMap();
	}
	
	/**
	 * 转换为Bean对象
	 * @param <T>
	 * @param bean Bean
	 * @return Bean
	 */
	public <T> T toBean(T bean) {
		return BeanUtils.toBean(bean, this);
	}
	/**
	 * 填充Value Object对象
	 * @return vo
	 */
	public <T> T toBean(Class<T> beanClass) {
		return BeanUtils.toBean(beanClass, this);
	}
	
	/**
	 * 将值对象转换为Params<br>
	 * 类名会被当作表名，小写第一个字母
	 * @param <T>
	 * @param bean 值对象
	 * @return 自己
	 */
	public <T> ParamMap parseBean(T bean) {
		if (null != bean) {
			this.putAll(BeanUtils.parse(bean));
		}
		return this;
	}
	/**
	 * 将值对象转换为Params<br>
	 * 类名会被当作表名，小写第一个字母
	 * 
	 * @param <T>
	 * @param map
	 *            值对象
	 * @return 自己
	 */
	public <T> ParamMap parseMap(Map<String, Object> map) {
		if (null != map) {
			this.putAll(map);
		}
		return this;
	}

	/**
	 * 封装分页参数
	 */
	public Map<String,Object> data(List list) {
	    Map<String,Object> paramMap = new HashMap<>();
        paramMap.put("pageNum",this.getPageNum());
        paramMap.put("pageSize",this.getPageSize());
        paramMap.put("list",list);
		if (list instanceof Page) {
			Page page = (Page) list;
			setPageNum(page.getPageNum());
			setPageSize(page.getPageSize());
		}
		return paramMap;
	}

	public Map<String,Object> dataEx(List list,Map<String, Object>  map){
        Map<String,Object> paramMap = new HashMap<String,Object>();
        map.put("pageNum",this.getPageNum());
        map.put("pageSize",this.getPageSize());
        map.put("list",this.getList());
        for(Entry<String, Object> entry:map.entrySet()){
            paramMap.put(entry.getKey(),entry.getValue());
        }
        if (list instanceof Page) {
            Page page = (Page) list;
            setPageNum(page.getPageNum());
            setPageSize(page.getPageSize());
        }
        return paramMap;
	}

    public List getList() {
        return (List) get("list");
    }
    public void setList(List list) {
        put("list", list);
    }
	public String getPageNum() {
		return (String)get("pageNum");
	}
	public void setPageNum(Integer pageNum) {
		put("pageNum", pageNum);
	}
	public String getPageSize() {
		return (String) get("pageSize");
	}
	public void setPageSize(Integer pageSize) {
		put("pageSize", pageSize);
	}
	public void setStr(String key,Object value) {
		put(key, value);
	}
	

	//-------------------------------------------------------------------- 特定类型值
	/**
	 * 设置列
	 * @param attr 属性
	 * @param value 值
	 * @return 本身
	 */
	public ParamMap set(String attr, Object value) {
		return this.put(attr, value);
	}
	
	
	/**
	 * 设置列，当键或值为null时忽略
	 * @param attr 属性
	 * @param value 值
	 * @return 本身
	 */
	public ParamMap setIgnoreNull(String attr, Object value) {
		if(null != attr && null != value) {
			set(attr, value);
		}
		return this;
	}
	
	/**
	 * 设置列
	 * @param attr 属性
	 * @param value 值
	 * @return 本身
	 */
	@Override
	public ParamMap put(String attr, Object value) {
		super.put(attr, value);
		return this;
	}

	/**
	 * 获得特定类型值
	 * @param attr 字段名
	 * @param defaultValue 默认值
	 * @return 字段值
	 */
	public <T> T get(String attr, T defaultValue) {
		final Object result = super.get(attr);
		return (T)(result != null ? result : defaultValue);
	}
	public Object get(String key) {
		return super.get(key);
	}
	
	public String getStr(String attr) {
		return getStr(attr, null);
	}
	public String getStr(String attr, String defaultVal) {
		return Convert.toStr(get(attr), defaultVal);
	}

	public Integer getInt(String attr) {
		return getInt(attr, null);
	}
	public Integer getInt(String attr, Integer defaultVal) {
		return Convert.toInt(get(attr), defaultVal);
	}
	
	public Long getLong(String attr) {
		return getLong(attr, null);
	}
	public Long getLong(String attr, Long defaultVal) {
		return Convert.toLong(get(attr), defaultVal);
	}
	
	public Float getFloat(String attr) {
		return getFloat(attr, null);
	}
	public Float getFloat(String attr, Float defaultVal) {
		return Convert.toFloat(get(attr), defaultVal);
	}
	
	public Short getShort(String attr) {
		return getShort(attr, null);
	}
	public Short getShort(String attr, Short defaultVal) {
		return Convert.toShort(get(attr), defaultVal);
	}

	public Character getChar(String attr) {
		return getChar(attr, null);
	}
	public Character getChar(String attr, Character defaultVal) {
		return Convert.toChar(get(attr), defaultVal);
	}

	public Double getDouble(String attr) {
		return getDouble(attr, null);
	}
	public Double getDouble(String attr, Double defaultVal) {
		return Convert.toDouble(get(attr), defaultVal);
	}

	public Byte getByte(String attr) {
		return getByte(attr, null);
	}
	public Byte getByte(String attr, Byte defaultVal) {
		return Convert.toByte(get(attr), defaultVal);
	}
	
	public Boolean getBool(String attr) {
		return getBool(attr, null);
	}
	public Boolean getBool(String attr, Boolean defaultVal) {
		return Convert.toBool(get(attr), defaultVal);
	}
	
	public BigDecimal getBigDecimal(String attr) {
		return getBigDecimal(attr, null);
	}
	public BigDecimal getBigDecimal(String attr, BigDecimal defaultVal) {
		return Convert.toBigDecimal(get(attr), defaultVal);
	}
	
	public BigInteger getBigInteger(String attr) {
		return getBigInteger(attr, null);
	}
	public BigInteger getBigInteger(String attr, BigInteger defaultVal) {
		return Convert.toBigInteger(get(attr), defaultVal);
	}
	
	public <E extends Enum<E>> E getEnum(Class<E> clazz, String key) {
		return Convert.toEnum(clazz, get(key));
	}
	public <E extends Enum<E>> E getEnum(Class<E> clazz, String key, E defaultVal) {
		return Convert.toEnum(clazz, get(key), defaultVal);
	}
	
	public byte[] getBytes(String attr) {
		return get(attr, null);
	}
	public byte[] getBytes(String attr, byte[] defaultVal) {
		return get(attr, defaultVal);
	}
	
	public Date getDate(String attr) {
		return get(attr, null);
	}
	public Date getDate(String attr, Date defaultVal) {
		return get(attr, defaultVal);
	}
	
	public Time getTime(String attr) {
		return get(attr, null);
	}
	public Time getTime(String attr, Time defaultVal) {
		return get(attr, defaultVal);
	}
	
	public Timestamp getTimestamp(String attr) {
		return get(attr, null);
	}
	public Timestamp getTimestamp(String attr, Timestamp defaultVal) {
		return get(attr, defaultVal);
	}
	
	public Number getNumber(String attr) {
		return get(attr, null);
	}
	public Number getNumber(String attr, Number defaultVal) {
		return get(attr, defaultVal);
	}
	
	
	
	/* ------------ valid get -----------------*/
	public Object getObjValid(String attr) {
		Object res = super.get(attr);
		if(res == null){
			throw new ParamException("Value for '" + attr + "' cannot be empty");
		}
		return res;
	}
	
	public String getStrValid(String attr) {
		String res = Convert.toStr(get(attr), null);
		return res;
	}

	public String getStrMisValid(String attr) {
		String res = Convert.toStr(get(attr), null);
		if(StringUtils.isBlank(res)){
			throw new ParamException(BizExceptionEnum.ISV_MISSING,attr);
		}
		return res;
	}

	public String getStrValid(String attr, String errmsg) {
		String res = Convert.toStr(get(attr), null);
		if(StringUtils.isBlank(res)){
			throw new ParamException(errmsg);
		}
		return res;
	}

	public Integer getIntMisValid(String attr) {
		Integer res = Convert.toInt(get(attr), null);
		if(res == null){
			throw new ParamException(BizExceptionEnum.ISV_MISSING,attr);
		}
		return res;
	}

	public Integer getIntValid(String attr) {
		Integer res = Convert.toInt(get(attr), null);
		if(res == null){
			return 0;
		}
		return res;
	}
	
	public Long getLongValid(String attr) {
		Long res = Convert.toLong(get(attr), null);
//		if(res == null){
//			throw new ParamException("Value for '" + attr + "' cannot be empty");
//		}
		return res;
	}

	public Long getLongMisValid(String attr) {
        Long res = Convert.toLong(get(attr), null);
		if(res == null){
			throw new ParamException(BizExceptionEnum.ISV_MISSING,attr);
		}
		return res;
	}
	
	public Float getFloatValid(String attr) {
		Float res = Convert.toFloat(get(attr), null);
		if(res == null){
			throw new ParamException("Value for '" + attr + "' cannot be empty");
		}
		return res;
	}
	
	public Short getShortValid(String attr) {
		Short res = Convert.toShort(get(attr), null);
		if(res == null){
			throw new ParamException("Value for '" + attr + "' cannot be empty");
		}
		return res;
	}

	public Character getCharValid(String attr) {
		Character res = Convert.toChar(get(attr), null);
		if(res == null){
			throw new ParamException("Value for '" + attr + "' cannot be empty");
		}
		return res;
	}

	public Double getDoubleValid(String attr) {
		Double res = Convert.toDouble(get(attr), null);
		if(res == null){
			throw new ParamException("Value for '" + attr + "' cannot be empty");
		}
		return res;
	}

	public Byte getByteValid(String attr) {
		Byte res = Convert.toByte(get(attr), null);
		if(res == null){
			throw new ParamException("Value for '" + attr + "' cannot be empty");
		}
		return res;
	}
	
	public Boolean getBoolValid(String attr) {
		Boolean res = Convert.toBool(get(attr), null);
		if(res == null){
			throw new ParamException("Value for '" + attr + "' cannot be empty");
		}
		return res;
	}
	
	public BigDecimal getBigDecimalValid(String attr) {
		BigDecimal res = Convert.toBigDecimal(get(attr));
		if(res == null){
			throw new ParamException("Value for '" + attr + "' cannot be empty");
		}
		return res;
	}
	
	public BigInteger getBigIntegerValid(String attr) {
		BigInteger res = Convert.toBigInteger(get(attr));
		if(res == null){
			throw new ParamException("Value for '" + attr + "' cannot be empty");
		}
		return res;
	}
	
	public <E extends Enum<E>> E getEnumValid(Class<E> clazz, String attr) {
		E res = Convert.toEnum(clazz, get(attr));
		if(res == null){
			throw new ParamException("Value for '" + attr + "' cannot be empty");
		}
		return res;
	}
	
	public byte[] getBytesValid(String attr) {
		byte[] res = get(attr, null);
		if(res.length == 0){
			throw new ParamException("Value for '" + attr + "' cannot be empty");
		}
		return res;
	}
	
	public Date getDateValid(String attr) {
		Date res = get(attr, null);
		if(res == null){
			throw new ParamException("Value for '" + attr + "' cannot be empty");
		}
		return res;
	}
	
	public Time getTimeValid(String attr) {
		Time res = get(attr, null);
		if(res == null){
			throw new ParamException("Value for '" + attr + "' cannot be empty");
		}
		return res;
	}
	
	public Timestamp getTimestampValid(String attr) {
		Timestamp res = get(attr, null);
		if(res == null){
			throw new ParamException("Value for '" + attr + "' cannot be empty");
		}
		return res;
	}
	
	public Number getNumberValid(String attr) {
		Number res = get(attr, null);
		if(res == null){
			throw new ParamException("Value for '" + attr + "' cannot be empty");
		}
		return res;
	}
	
	/* ------------ valid get -----------------*/
	
	
	
	//-------------------------get Map/List-------------------------\
	public List<Map> getListMap(String attr,String name) {
		try{
			List<Map> mapList = new ArrayList<>();
			List list = JSON.parseArray(attr);
			for(Object o:list){
				mapList.add((Map)o);
			}
			return mapList;
		} catch (Exception e) {
			throw new ParamException(BizExceptionEnum.ISV_ERROR,name);
		}

	}
	public Map<String, Object> getMapValid(String attr, String errmsg) {
		Map<String, Object> map = getMap(attr);
		if(map==null || map.isEmpty()) {
			throw new ParamException(errmsg);
		}
		return map;
	}
	@SuppressWarnings("unchecked")
	public Map<String, Object> getMap(String attr) {
		final Object result = super.get(attr);
		try {
			if (result instanceof Map) {
				return (Map<String, Object>) result;
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return new HashMap<String, Object>();
	}
	public ParamMap getParamMapValid(String attr, String errmsg) {
		ParamMap map = getParamMap(attr);
		if(map==null || map.isEmpty()) {
			throw new ParamException(errmsg);
		}
		return map;
	}
	@SuppressWarnings("unchecked")
	public ParamMap getParamMap(String attr) {
		try {
			final Object result = super.get(attr);
			if (result instanceof ParamMap) {
				return (ParamMap) result;
			} else if (result instanceof Map) {
				return new ParamMap((Map<String, Object>) result);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return init();
	}
	
	public List<ParamMap> getParamMapListValid(String attr, String errmsg) {
		List<ParamMap> list = getParamMapList(attr);
		if(list==null || list.isEmpty()) {
			throw new ParamException(errmsg); 
		}
		return list;
	}
	@SuppressWarnings("unchecked")
	public List<ParamMap> getParamMapList(String attr) {
		List<ParamMap> resultList = new ArrayList<ParamMap>();
		final Object list = get(attr);
		if(list instanceof List) {
			Iterator<?> it = ((List<?>) list).iterator();
			while (it.hasNext()) {
				try {
					Object element = (Object) it.next();
					if (element instanceof ParamMap) {
						resultList.add((ParamMap) element);
					}else if (element instanceof Map) {
						resultList.add(new ParamMap((Map<String, Object>) element));
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
		return resultList;
	}
	public List<String> getStrListValid(String attr, String errmsg) {
		List<String> list = getStrList(attr);
		if(list==null || list.isEmpty()) {
			throw new ParamException(errmsg); 
		}
		return list;
	}
	public List<String> getStrList(String attr) {
		List<String> resultList = new ArrayList<String>();
		final Object list = get(attr);
		if(list instanceof List) {
			Iterator<?> it = ((List<?>) list).iterator();
			while (it.hasNext()) {
				Object element = (Object) it.next();
				String ele = Convert.toStr(element);
				if(ele != null) {
					resultList.add(ele);
				}
			}
		}
		return resultList;
	}
	public List<Integer> getIntListValid(String attr, String errmsg) {
		List<Integer> list = getIntList(attr);
		if(list==null || list.isEmpty()) {
			throw new ParamException(errmsg); 
		}
		return list;
	}
	public List<Integer> getIntList(String attr) {
		List<Integer> resultList = new ArrayList<Integer>();
		final Object list = get(attr);
		if(list instanceof List) {
			Iterator<?> it = ((List<?>) list).iterator();
			while (it.hasNext()) {
				Object element = (Object) it.next();
				Integer ele = Convert.toInt(element);
				if(ele != null) {
					resultList.add(ele);
				}
			}
		}
		return resultList;
	}
	public List<Long> getLongListValid(String attr, String errmsg) {
		List<Long> list = getLongList(attr);
		if(list==null || list.isEmpty()) {
			throw new ParamException(errmsg); 
		}
		return list;
	}
	public List<Long> getLongList(String attr) {
		List<Long> resultList = new ArrayList<Long>();
		final Object list = get(attr);
		if(list instanceof List) {
			Iterator<?> it = ((List<?>) list).iterator();
			while (it.hasNext()) {
				Object element = (Object) it.next();
				Long ele = Convert.toLong(element);
				if(ele != null) {
					resultList.add(ele);
				}
			}
		}
		return resultList;
	}
	public List<Double> getDoubleListValid(String attr, String errmsg) {
		List<Double> list = getDoubleList(attr);
		if(list==null || list.isEmpty()) {
			throw new ParamException(errmsg); 
		}
		return list;
	}
	public List<Double> getDoubleList(String attr) {
		List<Double> resultList = new ArrayList<Double>();
		final Object list = get(attr);
		if(list instanceof List) {
			Iterator<?> it = ((List<?>) list).iterator();
			while (it.hasNext()) {
				Object element = (Object) it.next();
				Double ele = Convert.toDouble(element);
				if(ele != null) {
					resultList.add(ele);
				}
			}
		}
		return resultList;
	}
	public List<BigDecimal> getBigDecimalListValid(String attr, String errmsg) {
		List<BigDecimal> list = getBigDecimalList(attr);
		if(list==null || list.isEmpty()) {
			throw new ParamException(errmsg); 
		}
		return list;
	}
	public List<BigDecimal> getBigDecimalList(String attr) {
		List<BigDecimal> resultList = new ArrayList<BigDecimal>();
		final Object list = get(attr);
		if(list instanceof List) {
			Iterator<?> it = ((List<?>) list).iterator();
			while (it.hasNext()) {
				Object element = (Object) it.next();
				BigDecimal ele = Convert.toBigDecimal(element);
				if(ele != null) {
					resultList.add(ele);
				}
			}
		}
		return resultList;
	}
	//-------------------------get Map/List-------------------------
	
	
	@Override
	public ParamMap clone() {
		return (ParamMap) super.clone();
	}
	
}
